package common;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import math.AbstractEstimateIterMin;
import math.LeastSquareMethod;
import math.WLeastSquareMethod;
import math.common.MathCommon;
import math.probability.CompDistribution;
import math.probability.ExpDistribution;
import math.probability.NormalDistribution;
import math.probability.ProbDistribution;
import math.probability.UniformDistribution;

public class CovTest {
	
	ArrayList<Double> U; 
	ArrayList<Double> V;
	double meanU; 
	double meanV;
	
	private void modelData(ProbDistribution distX, ProbDistribution distKsi, 
			ProbDistribution distEps, int N, Double b0, Double b1) {
		U = new ArrayList<Double>(); 
		V = new ArrayList<Double>();
		ArrayList<Double> smplX = distX.getSample(N);
		ArrayList<Double> ksi = distKsi.getSample(N);
		ArrayList<Double> eps = distEps.getSample(N);
		double sumU = 0.0;
		double sumV = 0.0;
		for (int i = 0; i < N; i++) {
			V.add(b0+b1*smplX.get(i) + eps.get(i));
			U.add(smplX.get(i) + ksi.get(i));
			sumU += U.get(i);
			sumV += V.get(i);
		}
		meanU = sumU/N; 
		meanV = sumV/N;
		for (int i = 0; i < N; i++) {
			V.set(i, V.get(i)-meanV); 
			U.set(i, U.get(i)-meanU);
		}
		
	}
	
	private void modelData(ProbDistribution distX, ProbDistribution distKsi, 
			ProbDistribution distEps, int N, Double b0, Double b1, Random r) {
		U = new ArrayList<Double>(); 
		V = new ArrayList<Double>();
		ArrayList<Double> smplX = distX.getSample(N,r);
		ArrayList<Double> ksi = distKsi.getSample(N,r);
		ArrayList<Double> eps = distEps.getSample(N,r);
		double sumU = 0.0;
		double sumV = 0.0;
		for (int i = 0; i < N; i++) {
			V.add(b0+b1*smplX.get(i) + eps.get(i));
			U.add(smplX.get(i) + ksi.get(i));
			sumU += U.get(i);
			sumV += V.get(i);
		}
		meanU = sumU/N; 
		meanV = sumV/N;
		for (int i = 0; i < N; i++) {
			V.set(i, V.get(i)-meanV); 
			U.set(i, U.get(i)-meanU);
		}
//		System.out.println("V  U  X  ksi");
//		for (int i=0; i<U.size(); i++) {
//			System.out.println(V.get(i)+"  "+U.get(i)+"  "+smplX.get(i)+"  "+ksi.get(i) );
//		}
		
	}
	
	Double getCorrelation (List<Double> x, List<Double> y) {
		Double sum = 0.0;
		Double mX = 0.0;
		Double mY = 0.0;
		Double dX = 0.0;
		Double dY = 0.0;
		int n = x.size();
		for (int i = 0; i < n; i++ ) {
			mX += x.get(i);
			mY += y.get(i);
		}
		mX = mX/n;
		mY = mY/n;
		for (int i = 0; i < n; i++ ) {
			sum += (x.get(i)-mX)*(y.get(i)-mY);
			dX += Math.pow(x.get(i)-mX, 2.0);
			dY += Math.pow(y.get(i)-mY, 2.0);
		}
		return (n-1)*sum/(n*Math.sqrt(dX*dY));
	}
	
	Double getCov (List<Double> x, List<Double> y) {
		Double sum = 0.0;
		Double mX = 0.0;
		Double mY = 0.0;
		Double dX = 0.0;
		Double dY = 0.0;
		int n = x.size();
		for (int i = 0; i < n; i++ ) {
			mX += x.get(i);
			mY += y.get(i);
		}
		mX = mX/n;
		mY = mY/n;
		for (int i = 0; i < n; i++ ) {
			sum += (x.get(i)-mX)*(y.get(i)-mY);
			
		}
		return sum/n;
	}
	
	Double getVar (List<Double> x) {
		Double mX = 0.0;
		Double dX = 0.0;
		int n = x.size();
		for (int i = 0; i < n; i++ ) {
			mX += x.get(i);
		}
		mX = mX/n;
		for (int i = 0; i < n; i++ ) {
			dX += Math.pow(x.get(i)-mX, 2.0);
		}
		return dX/(n-1);
		
	}
	
	void doTest () {
		int N = 100;
		int M = 10000;
		Double b0 = 0.0;
		Double b1 = 10.0;
		Random rnd = new Random();
		ProbDistribution distX = new ExpDistribution(0.75);
		ProbDistribution distEps = new NormalDistribution(0.0,0.1);
		ProbDistribution distKsi = new NormalDistribution(0.0, 1.0);
		int f = 0;
		Double S = 0.0;
		for (int j=0; j<M; j++) {
			modelData (distX,distKsi,distEps, N, b0, b1,rnd);

			
			Double b = new WLeastSquareMethod().estimate(V, U);
			ArrayList<Double> er = new ArrayList<Double>();
			for (int k=0; k<U.size(); k++) {
				er.add(V.get(k) - b*U.get(k));
			}

//			Double r = getCorrelation(U,er);
			Double r = getCov(U,er);
			S+=r;
		//	Double t = r*Math.sqrt((N-2)/(1-r*r));
			
			//if (Math.abs(t)< 2) 
				//f++;
			
//			if (Math.abs(t)< 2) 	
//				System.out.println (j + "  " + r + "  " + t + "  H0");
//			else
//				System.out.println (j + "  " + r + "  " + t + "  H1");

		}
		//System.out.println(f/(double)M + "," + (M-f)/(double)M);
		System.out.println(S/M);
	}
	
	void doTest1() throws FileNotFoundException {
		int N = 50;
		int M = 500;
		Double b0 = 0.0;
		Double b1 = 10.0;
		ProbDistribution distX = new ExpDistribution(0.75);
		ProbDistribution distEps = new NormalDistribution(0.0,0.1);
		ProbDistribution distKsi = new NormalDistribution(0.0, 1.0);
		PrintWriter out = new PrintWriter(new FileOutputStream("tH1.csv", true));
		out.println("tH1");
		int f = 0;
		for (int j=0; j<M; j++) {
			modelData (distX,distKsi,distEps, N, b0, b1);
			Double U2 = 0.0;
			Double U6 = 0.0;
			Double U4 = 0.0;
			Double b11 = new LeastSquareMethod().estimate(V, U);
			Double b12 = new WLeastSquareMethod().estimate(V, U);
			ArrayList<Double> er1 = new ArrayList<Double>();
			ArrayList<Double> er2 = new ArrayList<Double>();
			for (int k=0; k<U.size(); k++) {
				er1.add(V.get(k) - b11*U.get(k));
				er2.add(V.get(k) - b12*U.get(k));
				U2 += Math.pow(U.get(k), 2.0);
				U4 += Math.pow(U.get(k), 4.0);
				U6 += Math.pow(U.get(k), 6.0);
			}
			U2 = 1.0/U2;
			U4 = U6/(U4*U4);
			Double s1 = getVar(er1);
			Double s2 = getVar(er2);
			Double t = Math.pow(b12-b11,2.0)/(s1*(U4-U2));
//			Double t = Math.pow((b12-b11)/0.023428616,2.0);
			out.println(t);
			
//			if (t < 3.8415) 
//				System.out.printf("b11=%f.4  b12=%f.4  t=%f.4  H0  D=%f.4\n",b11,b12,t,s1*(U4-U2));
////				System.out.println (j + "  b11=" + b11 + "  b12=" + b12 + "  " + t + "  H0" + " D=" + s1*(U4-U2));
//			else
////				System.out.println (j + "  b11=" + b11 + "  b12=" + b12 + "  "  + t + "  H1" + " D=" + s1*(U4-U2));	
//				System.out.printf("b11=%f.4  b12=%f.4  t=%f.4  H1  D=%f.4\n",b11,b12,t,s1*(U4-U2));
		}
		out.flush();
		out.close();
	}
	
	Double getT (Double est1, Double est2) {
		Double U2 = 0.0;
		Double U6 = 0.0;
		Double U4 = 0.0;
		Double b01 = meanV - meanU*est1;
		ArrayList<Double> er = new ArrayList<Double>();
		for (int k=0; k<U.size(); k++) {
			er.add(V.get(k) - est1*U.get(k)-b01);
			U2 += Math.pow(U.get(k), 2.0);
			U4 += Math.pow(U.get(k), 4.0);
			U6 += Math.pow(U.get(k), 6.0);
		}
		U2 = 1.0/U2;
		U4 = U6/(U4*U4);
		Double s1 = getVar(er);
		Double t = Math.pow(est1-est2,2.0)/(s1*(U4-U2));
		return t;
	}
	Double getF (Double est1, Double est2) {
		Double U2 = 0.0;
		Double U6 = 0.0;
		Double U4 = 0.0;
		Double b01 = meanV - meanU*est1;
		ArrayList<Double> er = new ArrayList<Double>();
		for (int k=0; k<U.size(); k++) {
			er.add(V.get(k) - est1*U.get(k)-b01);
			U2 += Math.pow(U.get(k), 2.0);
			U4 += Math.pow(U.get(k), 4.0);
			U6 += Math.pow(U.get(k), 6.0);
		}
		U2 = 1.0/U2;
		U4 = U6/(U4*U4);
		Double s1 = getVar(er);
		Double t = Math.pow(est1/est2,2.0)*(U4/U2)-1;
		return t;
	}
	
	void TestCoeffEq() throws FileNotFoundException {
		int N = 50;
		int M = 500;
		Double b0 = 0.0;
		Double b1 = 10.0;
		
		
		Double b11;
		Double b12;
//		ProbDistribution distX = new ExpDistribution(0.3);
		ProbDistribution distX = new UniformDistribution(1.0, 10.0);
		ProbDistribution distEps = new NormalDistribution(0.0,0.1);
		PrintWriter out = new PrintWriter(new FileOutputStream("TestCoeffEq.csv", true));
		
		out.println("X,b1, sKsi2, alpha,beta");
		double a[] = {0.5d, 1d, 1.5d};
		for (double sKsi2 : a) {
		int falseH0 = 0;
		int falseH1 = 0;
		for (int j=0; j<M; j++) {
			//H0
			ProbDistribution distKsi0 = new NormalDistribution(0.0, 0.0);
			modelData (distX,distKsi0,distEps, N, b0, b1);
			b11 = new LeastSquareMethod().estimate(V, U);
			b12 = new WLeastSquareMethod().estimate(V, U);
			Double tH0 = getT(b11, b12); 
//			out.print(tH0 + "," + Math.pow(b11-b12, 2) + "," + b11 + "," + b12 + ",");
			//H1
			ProbDistribution distKsi = new NormalDistribution(0.0, 1.0);
			modelData (distX,distKsi,distEps, N, b0, b1);
			b11 = new LeastSquareMethod().estimate(V, U);
			b12 = new WLeastSquareMethod().estimate(V, U);
			Double tH1 = getT(b11, b12);
//			out.println(tH1 + "," + Math.pow(b11-b12, 2) + "," + b11 + "," + b12);
			
			
			if (tH0 > 3.8415)
				falseH0++;
			if (tH1 < 3.8415)
				falseH1++;
			
		}
		out.println(distX.toString() + "," + b1 + "," + sKsi2 + "," + (double)falseH0/M + "," + (double)falseH1/M);
		}
		out.flush();
		out.close();
		
	}
	
	void TestResiduals() throws FileNotFoundException {
		int N = 50;
		int M = 1;
		Double b0 = 0.0;
		Double b1 = 1.0;
		
		
		Double b11;
		Double b12;
		ProbDistribution distX = new ExpDistribution(0.75);
		ProbDistribution distEps = new NormalDistribution(0.0,0.1);
		PrintWriter out = new PrintWriter(new FileOutputStream("TestResiduals.csv", true));
		
//		out.println("tH0,difH0,bH0,bWH0,tH1,difH1,bH1,bWH1");
		
		int falseH0 = 0;
		int falseH1 = 0;
		for (int j=0; j<M; j++) {
			//H0
			ProbDistribution distKsi0 = new NormalDistribution(0.0, 0.0);
			modelData (distX,distKsi0,distEps, N, b0, b1);
			b11 = new LeastSquareMethod().estimate(V, U);
			ArrayList<Double> erH0 = new ArrayList<Double>();
			for (int i=0; i<U.size(); i++) {
				erH0.add(V.get(i)-b11*U.get(i));
				out.println("H0," + erH0.get(i));
			}
			//H1
			ProbDistribution distKsi = new NormalDistribution(0.0, 1.0);
			modelData (distX,distKsi,distEps, N, b0, b1);
			b11 = new LeastSquareMethod().estimate(V, U);
			ArrayList<Double> erH1 = new ArrayList<Double>();
			for (int i=0; i<U.size(); i++) {
				erH1.add(V.get(i)-b11*U.get(i));
				out.println("H1," + erH1.get(i));
			}
			
			
			
		}
		out.flush();
		out.close();
//		System.out.println("alpha:" + (double)falseH0/M + "  beta:" + (double)falseH1/M);
	}
	
	public static void main(String arg[]) throws FileNotFoundException {
		CovTest test = new CovTest();
		test.TestCoeffEq();
	
	}
}
